home *** CD-ROM | disk | FTP | other *** search
/ PC Welt 2001 September / PC-WELT 9-2001.ISO / software / hw / brennen / flask_src.exe / Subpic / Subpic.cpp next >
Encoding:
C/C++ Source or Header  |  2000-06-26  |  15.0 KB  |  597 lines

  1. /* 
  2.  *  Subpic.cpp: subpic decoding
  3.  *
  4.  *    Copyright (C) Glenn Maynard - May 2000 - glennm@mediaone.net
  5.  *
  6.  *  With the help of Helmet (ezrd@hotmail.com)
  7.  *
  8.  *  This file is part of FlasKMPEG, a free MPEG to MPEG/AVI converter
  9.  *    
  10.  *  FlasKMPEG is free software; you can redistribute it and/or modify
  11.  *  it under the terms of the GNU General Public License as published by
  12.  *  the Free Software Foundation; either version 2, or (at your option)
  13.  *  any later version.
  14.  *   
  15.  *  FlasKMPEG is distributed in the hope that it will be useful,
  16.  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
  17.  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  18.  *  GNU General Public License for more details.
  19.  *   
  20.  *  You should have received a copy of the GNU General Public License
  21.  *  along with GNU Make; see the file COPYING.  If not, write to
  22.  *  the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. 
  23.  *
  24.  */
  25.  
  26. #include <crtdbg.h>
  27.  
  28. #include "subpic.h"
  29. extern "C"
  30. {
  31. #include "..\video\config.h"
  32. #include "..\video\global.h"
  33. }
  34.  
  35. struct subpic_t {
  36.     unsigned char *bitmap;
  37.     int x, y; /* dimensions */
  38.     int sX, sY; /* coordinates */
  39.     int start, stop; /* start and stop time */
  40.  
  41.     unsigned char colors[4]; /* palette */
  42.     unsigned char alpha[4]; /* alpha channel */
  43.     struct subpic_t *next, *prev;
  44. };
  45.  
  46. #include "..\runstate.h"
  47. extern TRunState rs;
  48. static struct subpic_t *pics = NULL;
  49.  
  50. /* grab a nibble from buf */
  51. static unsigned char grab_nibble(const unsigned char *buf, unsigned &offset, bool &aligned)
  52. {
  53.     unsigned char c;
  54.     if(aligned) c = buf[offset] >> 4;
  55.     else {
  56.         c = buf[offset] & 0xF;
  57.         offset++;
  58.     }
  59.     aligned = !aligned;
  60.  
  61.     return c;
  62. }
  63.  
  64. static struct subpic_t *free_subpic(struct subpic_t *s)
  65. {
  66.     struct subpic_t *next;
  67.  
  68.     if(s == NULL) return NULL;
  69.  
  70.     next = s->next;
  71.  
  72.     if(s->prev) s->prev->next = s->next;
  73.     if(s->next) s->next->prev = s->prev;
  74.     if(s == pics) pics=pics->next;
  75.  
  76.     if(s->bitmap) free(s->bitmap);
  77.     free(s);
  78.  
  79.     return next;
  80. }
  81.  
  82. /* free all subpics */
  83. void subpic_free(void)
  84. {
  85.     while(pics) pics=free_subpic(pics);
  86.  
  87.     pics = NULL;
  88. }
  89.  
  90. /* subpic init  */
  91. /*   A.V. modif */
  92. static unsigned char palette[16][3];
  93. void subpic_init(void)
  94. {
  95.     if(rs.ifo == NULL) return; /* no IFO, no subtitles */
  96.  
  97.     // Work out RGB palette from IFO YUV palette
  98.     for(int i = 0; i < 16; i++) {
  99.         int crv = 117504, cbu = 138453, cgu = 13954, cgv = 34903;
  100.  
  101.         int  u = (unsigned char)rs.ifo->pgcs[rs.DVDSelections.selected_pgc].clut[i][3] - 128;
  102.         int  v = (unsigned char)rs.ifo->pgcs[rs.DVDSelections.selected_pgc].clut[i][2] - 128;
  103.         int  y = 76309 * ((unsigned char)rs.ifo->pgcs[rs.DVDSelections.selected_pgc].clut[i][1] - 16);
  104.  
  105.         palette[i][0] = Clip[(y + crv*v         + 32768)>>16];
  106.         palette[i][1] = Clip[(y - cgu*u - cgv*v + 32768)>>16];
  107.         palette[i][2] = Clip[(y + cbu*u         + 32768)>>16];
  108.     }
  109. }
  110.  
  111.  
  112.  
  113. static void subpic_apply(VBitmap *p, int tm, struct subpic_t *s)
  114. {
  115.     for(int x = 0; x < s->x; x++) {
  116.         for(int y = 0; y < s->y; y++) {
  117.             int pcolor = s->bitmap[y*s->x + x]; /* subpic palette index (0-3) */
  118.  
  119.             int alpha = s->alpha[pcolor];
  120.             if(alpha == 0x0) 
  121.                 // alpha = 0xFF;
  122.                 continue; /* don't waste time on completely transparent pixels */
  123.  
  124.             /* coords in the bitmap, of this pixel of the subpic:
  125.              * X = s->sX + x
  126.              * Y = p->h - (s->sY + y)
  127.              * 
  128.              * offset into it is Y * p->w + X:
  129.              * (p->h - (s->sY + y)) * p->w + (s->sX + x)
  130.              *
  131.              * get a pointer to the current pixel
  132.              */
  133.             
  134.             unsigned long *c = &p->data
  135.                 [(p->h - (s->sY + y)) * p->w +
  136.                  (s->sX + x)];
  137.             
  138.             pcolor = s->colors[pcolor]; /* convert subpic palette index into master palette */            
  139.  
  140.             unsigned char color[4];
  141.             /* palette[pcolor][] is the color being applied;
  142.              * p->data[Y * p->w + X][] is the color being applied to
  143.              */
  144.             *((unsigned long *)color) = *c;
  145.             long clr = 0;
  146.             for(int i = 0; i < 3; i++) {
  147.                 clr <<= 8;
  148.                 clr += (color[i] * (0xFF - alpha)) / 0xFF;
  149.                 clr += (palette[pcolor][i] * alpha) / 0xFF;
  150.             }
  151.  
  152.             *c = clr;
  153.         }
  154.     }
  155. }
  156.  
  157. void subpic_apply(VBitmap *p, int tm)
  158. {
  159.     struct subpic_t *s, *next;
  160.     if(rs.ifo == NULL) return; /* no IFO, no subtitles */
  161.  
  162.     for(s = pics; s; s=next) {
  163.         next=s->next;
  164.  
  165.         if(tm < s->start) continue; /* not yet */
  166.  
  167.         if(tm < s->stop) {
  168.             subpic_apply(p, tm, s);
  169.             continue;
  170.         }
  171.  
  172.         /* pic done */        
  173.         next = free_subpic(s);
  174.     }
  175. }
  176.  
  177. /* Parse a buffer into a bufpic.  Return -1 on error (can't parse), 0 on incomplete
  178.  * buffer, or 1 on success. On success, the subpic will be in pic; on error, pic
  179.  * may have a bitmap allocated ( != NULL), and should be freed.
  180.  *
  181.  * buf is the actual buffer; bufsiz is its length.
  182.  * tm is the time, in ms, of this packet, from the start of the stream; used for
  183.  * computing start and stop times. */
  184.  
  185. static int do_subpic_decode(const unsigned char *buf, size_t bufsiz, int tm,
  186.                             struct subpic_t *pic)
  187. {
  188.     unsigned dataLen;
  189.     
  190.     if(bufsiz < 4) return -1; /* way too short */
  191.     /* grab the length of the data packet */
  192.     dataLen = (buf[2] << 8) + buf[3];
  193.  
  194.     if(dataLen > bufsiz) return 0; /* incomplete */
  195.  
  196.     /* set default values */
  197.  
  198.     memset(pic, 0, sizeof(struct subpic_t));
  199.     pic->x = pic->y = pic->sX =  pic->sY = -1; /* required values */
  200.     pic->start = pic->stop = -1;
  201.  
  202.     /* parse the control packet */
  203.     unsigned offset[2];
  204.     bool control_done = false;
  205.     unsigned i = dataLen;
  206.  
  207.     /* for dupe offset checking */
  208.     unsigned offsets_done[255];
  209.     int offsets_done_n = 0;
  210.  
  211.     while(!control_done) {
  212.             unsigned start = i; /* offset of this sequence */
  213.             
  214.             /* decode each sequence of the control block */
  215.             bool control_sequence_done = false;
  216.  
  217.             if(i+4 >= bufsiz) return -1;
  218.  
  219.             int seq_time = 0;            
  220.             seq_time += buf[i++] << 8;
  221.             seq_time += buf[i++];
  222.  
  223. #define SUB_PRECISION 88.0
  224.             /* subpic timing is in 1/SUB_PRECISION of a second; convert to
  225.              * ms */
  226.  
  227.             seq_time = (int) (((double)seq_time / SUB_PRECISION) * 1000.0);
  228.  
  229.             /* convert PTS to it's in 1/SUB_PRECISION of a second; we want references to
  230.              * the 27Mhz MPEG2 reference clock */
  231.             // seq_time *= 27000;
  232.  
  233.             unsigned next = 0; /* offset to the next sequence, or to this one if last */
  234.             next += buf[i++] << 8;
  235.             next += buf[i++];
  236.             if(next > bufsiz) return 0; /* incomplete */
  237.  
  238.             /* if it's the same as this, then this is the last */
  239.             if(next == start) control_done = true;
  240.             
  241.             /* if next is in the data packet, we have a problem */
  242.             if(next < dataLen) {
  243.                 _RPT2(0, "Invalid next %u (dataLen %u)\n", next, dataLen);
  244.                 return -1;
  245.             }
  246.  
  247.             /* make sure we're not looping */
  248.             for(int n = 0; n < offsets_done_n; n++) {
  249.                 if(offsets_done[n] == start) {
  250.                     /* oops */
  251.                     _RPT1(0, "next %u encountered twice; looping\n", next);
  252.                     return -1;
  253.                 }
  254.             }
  255.             /* add after the check: it's OK to receive the *current* start as
  256.              * the next (it indicates last packet) */
  257.             offsets_done[offsets_done_n++] = start;
  258.             
  259.             while(!control_sequence_done) {
  260.                 unsigned char c;
  261.                 if(i >= bufsiz) return -1;
  262.                 c = buf[i++];
  263.                 bool aligned = true;
  264.  
  265.                 switch(c) {
  266.                 case 1: /* start time */
  267.                     pic->start = seq_time + tm;
  268.                     _RPT1(0, "Subpic starts on %x\n", pic->start);
  269.                     break;
  270.  
  271.                 case 2: /* stop time */
  272.                     pic->stop = seq_time + tm;
  273.                     break;
  274.  
  275.                 case 3: {
  276.                     /* palette */
  277.                     if(i+1 >= bufsiz) return -1;
  278.                     for(int p = 3; p >= 0; p--) {
  279.                         pic->colors[p] = grab_nibble(buf, i, aligned);
  280.                     }    
  281.                     
  282.                     break;
  283.                 }
  284.                 case 4: {
  285.                     /* transparency palette (?) */
  286.                     if(i+1 >= bufsiz) return -1;
  287.  
  288.                     /* we want 8 bit alpha, not 4, for future features */
  289.                     for(int p = 3; p >= 0; p--) {                        
  290.                         pic->alpha[p] = (int) (((double)grab_nibble(buf, i, aligned) / 15.0) * 255);
  291.                     }
  292.  
  293.                     break;
  294.                 }
  295.                 case 5: /* image coordinates */
  296.                     /* width */
  297.                     int endX, endY;
  298.                     if(i+5 >= bufsiz) return -1;
  299.     
  300.                     pic->sX = (grab_nibble(buf, i, aligned) << 8) + 
  301.                               (grab_nibble(buf, i, aligned) << 4) +
  302.                               grab_nibble(buf, i, aligned);
  303.  
  304.                     endX = (grab_nibble(buf, i, aligned) << 8) + 
  305.                            (grab_nibble(buf, i, aligned) << 4) +
  306.                               grab_nibble(buf, i, aligned);
  307.  
  308.                     pic->sY = (grab_nibble(buf, i, aligned) << 8) + 
  309.                               (grab_nibble(buf, i, aligned) << 4) +
  310.                               grab_nibble(buf, i, aligned);
  311.                     
  312.                     endY = (grab_nibble(buf, i, aligned) << 8) + 
  313.                            (grab_nibble(buf, i, aligned) << 4) +
  314.                               grab_nibble(buf, i, aligned);
  315.     
  316.                     pic->x = 1 + endX - pic->sX;
  317.                     pic->y = 1 + endY - pic->sY;
  318.     
  319.                     break;
  320.                 case 0x06: /* image 1 / image 2 offsets */
  321.                     if(i+1 >= bufsiz) return -1;
  322.                     offset[0] = ((unsigned int)buf[i++]) << 8;
  323.                     offset[0] += buf[i++];
  324.                     offset[1] = ((unsigned int)buf[i++]) << 8;
  325.                     offset[1] += buf[i++];
  326.                     break;
  327.                 case 0x07: /* unknown; appears to be 3 bytes */
  328.                     if(i+2 >= bufsiz) return -1;
  329.                     i += 3;
  330.                     break;
  331.     
  332.                 case 0xff: /* end of sequence */                    
  333.                     control_sequence_done = true;
  334.                     break;
  335.  
  336.                 default:
  337.                     /* we can't continue parsing past unknown commands
  338.                      * because we need their length.  we can try to display
  339.                      * them anyway, hoping we already have sufficient data--
  340.                      * if we don't, we'll bail anyway.  at least in my test DVDs,
  341.                      * control sequences appear generally sorted numerically, so
  342.                      * unless we hit c == 0 somehow, we might be OK */
  343.                     _RPT1(0, "Unknown subpic command: %2.2x\n", c);
  344.                     control_done = control_sequence_done = true;
  345.                 }
  346.             }
  347.             i = next;    
  348.     }
  349.  
  350.     /* sanity */
  351.     if(pic->x == -1 || pic->y == -1 || pic->sX == -1 || pic->sY == -1 ||
  352.         pic->start == -1 || pic->stop == -1) {
  353.         /* some required piece of data is missing */
  354.         _RPT0(0, "subpic data missing\n");
  355.         return -1;
  356.     }
  357.  
  358.     /* now we can alloc the bitmap */
  359.     pic->bitmap = (unsigned char *)malloc(pic->x * pic->y);
  360.     memset(pic->bitmap, 0, pic->x * pic->y);
  361.  
  362.     int x = 0, y = 0;
  363.     /* note: all Y wrapping is done in twos, since the pic is interlaced.
  364.      * do even.scanlines first, then odd
  365.      */
  366.     
  367.     int state = 0;
  368.     bool aligned = true;
  369.     if(offset[0] >= bufsiz) return -1;
  370.     if(offset[1] >= bufsiz) return -1;
  371.  
  372.     i = offset[state];
  373.     while(1) {
  374.         unsigned short val;
  375.  
  376.         do{
  377.             if(i >= bufsiz) return -1;
  378.             val = grab_nibble(buf, i, aligned);
  379.             if(val >= 0x004) break;    /* one-byte */
  380.  
  381.             if(i >= bufsiz) return -1;
  382.             val = (val << 4) + grab_nibble(buf, i, aligned);
  383.             if(val >= 0x010) break;    /* two-byte, 1x .. 3x */
  384.  
  385.             if(i >= bufsiz) return -1;
  386.             val = (val << 4) + grab_nibble(buf, i, aligned);
  387.             if(val >= 0x040) break; /* three-byte, 04x .. 0fx */
  388.             
  389.             if(i >= bufsiz) return -1;
  390.             val = (val << 4) + grab_nibble(buf, i, aligned);
  391.             if(val >= 0x100) break; /* four-byte, 01xx .. 03xx */
  392.             /* four-byte, 00xx */
  393.             if(val != 0) {
  394.                 _RPT1(0, "Invalid subpic data: %x\n", val);
  395.                 return -1;
  396.             }            
  397.         } while(0);
  398.         int pixNum = val >> 2;
  399.         int color = val & 3;
  400.         if(pixNum == 0) pixNum = pic->x - x; /* line feed */
  401.         if(pixNum + x > pic->x)
  402.             pixNum = pic->x - x; /* shouldn't happen: cap pixNum */
  403.             
  404.         while(pixNum--) {
  405.             pic->bitmap[y * pic->x + x] = color;
  406.             x++;
  407.             if(x == pic->x) {
  408.                 /* wrap */
  409.                 x = 0;
  410.                 y += 2;
  411.                 if(y > pic->y) break;
  412.                 if(!aligned) {
  413.                     if(i >= bufsiz) return -1;
  414.                     grab_nibble(buf, i, aligned);
  415.                 }
  416.             }
  417.         }
  418.         if(y >= pic->y) {
  419.             /* hit the bottom */
  420.             state++;
  421.             if(state == 2) break; /* done */
  422.             /* finished even; do odd */
  423.             y = 1;
  424.             i = offset[state];
  425.         }
  426.     }
  427.  
  428.     return 1;
  429. }
  430.  
  431. /* subpics often have lots of unused blank space on the borders.
  432.  * remove it. */
  433. static void subpic_squeeze(struct subpic_t *s)
  434. {
  435.     int newX = 0, newY = 0,
  436.         newSX = s->sX, newSY = s->sY; /* newX and newY is the new size; newSX and newSY
  437.                                        * are the offsets from the top and left of the old
  438.                                        * image */
  439.     bool nontrans = false;
  440.     int x, y;
  441.     for(y = 0; y < s->y; y++) {
  442.         for(x = 0; x < s->x; x++) {
  443.             int pcolor = s->bitmap[y*s->x + x]; /* subpic palette index (0-3) */
  444.             if(s->alpha[pcolor] != 0x0) {
  445.                 nontrans = true;
  446.                 break;
  447.             }
  448.         }
  449.         if(nontrans) break;
  450.     }
  451.     newSY = y;
  452.  
  453.     /* bottom */
  454.     nontrans = false;
  455.     for(y = s->y-1; y >= newSY; y--) {
  456.         for(x = 0; x < s->x; x++) {
  457.             int pcolor = s->bitmap[y*s->x + x]; /* subpic palette index (0-3) */
  458.             if(s->alpha[pcolor] != 0x0) {
  459.                 nontrans = true;
  460.                 break;
  461.             }
  462.         }
  463.         if(nontrans) break;
  464.     }
  465.     newY = y - newSY + 1;
  466.     
  467.     /* left */
  468.     nontrans = false;
  469.     for(x = 0; x < s->x; x++) {
  470.         for(y = 0; y < s->y; y++) {
  471.             int pcolor = s->bitmap[y*s->x + x]; /* subpic palette index (0-3) */
  472.             if(s->alpha[pcolor] != 0x0) {
  473.                 nontrans = true;
  474.                 break;
  475.             }
  476.         }
  477.         if(nontrans) break;
  478.     }
  479.  
  480.     newSX = x;
  481.  
  482.     /* right */
  483.     nontrans = false;
  484.     for(x = s->x-1; x > newSX; x--) {
  485.         for(y = 0; y < s->y; y++) {
  486.             int pcolor = s->bitmap[y*s->x + x]; /* subpic palette index (0-3) */
  487.             if(s->alpha[pcolor] != 0x0) {
  488.                 nontrans = true;
  489.                 break;
  490.             }
  491.         }
  492.         if(nontrans) break;
  493.     }
  494.     newX = x - newSX + 1;
  495.  
  496.     /* alloc new image */
  497.     unsigned char *newbitmap = (unsigned char *)malloc(newX * newY);
  498.     for(y = 0; y < newY; y++) {
  499.         for(x = 0; x < newX; x++) {
  500.             newbitmap[y*newX+x] = s->bitmap[(newSY+y)*s->x+(newSX+x)];
  501.         }
  502.     }
  503.  
  504.     s->x = newX;
  505.     s->y = newY;
  506.     s->sX += newSX;
  507.     s->sY += newSY;
  508.  
  509.     free(s->bitmap);
  510.     s->bitmap = newbitmap;
  511. }
  512.  
  513. static unsigned char subPicBuf[64000];
  514. static int subPicLen = 0;
  515.  
  516. int subpic_decode(const unsigned char *buf, size_t bufsiz, int tm)
  517. {
  518.     struct subpic_t *pic = new struct subpic_t;
  519.     static int start_time = 0;
  520.  
  521.     if(rs.ifo == NULL) return -1; /* no IFO, no subtitles */
  522.  
  523.     pic->bitmap = NULL;
  524.  
  525.     if(subPicLen + bufsiz >= 64000) {
  526.         /* overflow */
  527.         bufsiz = 0;
  528.         return -1;
  529.     }
  530.  
  531.     if(!start_time && !tm) {
  532.         /* this isn't a start packet, and we don't have one yet; it's
  533.          * mid-packet.  discard it. */
  534.         return -1;
  535.     }
  536.  
  537.     if(tm)
  538.     {
  539.         start_time=tm;
  540.         subPicLen = 0;
  541.     }
  542.     _RPT1(0, "? Subpic starts on %x\n", tm);
  543.     memmove(subPicBuf+subPicLen, buf, bufsiz);
  544.     subPicLen += bufsiz;
  545.  
  546.     int ret = do_subpic_decode(subPicBuf, subPicLen, start_time, pic);
  547.  
  548.     if(ret == -1 || ret > 0) {
  549.         if(ret == -1)
  550.             int z = 1; /* debug breakpoint target */
  551.         subPicLen = 0; /* error or success; clear the buffer */
  552.     }
  553.     if(ret <= 0) {
  554.         /* error or incomplete */
  555.         if(pic->bitmap != NULL) free(pic->bitmap);
  556.         delete pic;
  557.  
  558.         return ret;
  559.     }
  560.  
  561.     /* success; store it */
  562.     start_time = 0;
  563.     subpic_squeeze(pic);
  564.  
  565. #if 0
  566.     {
  567.         FILE *f;
  568.         f = fopen("C:\\TEMP\\SUB.TXT", "w+");
  569.         int x, y;
  570.         for(y = 0; y < pic->y; y++) {
  571.             for(x = 0; x < pic->x; x++) {
  572.                 char c = pic->bitmap[y*pic->x + x]+'0';
  573.                 if(c == '0') c = ' ';
  574.                 fprintf(f, "%c", c);
  575.             }
  576.             fprintf(f, "\n");
  577.         }
  578.         fprintf(f, "------------------------------------\n");
  579.         for(y = 0; y < pic->y; y++) {
  580.             for(x = 0; x < pic->x; x++) {
  581.                 fprintf(f, "%c", pic->alpha[pic->bitmap[y*pic->x + x]] == 0x0? '0':'1');                
  582.             }
  583.             fprintf(f, "\n");
  584.         }
  585.         fclose(f);
  586.     }
  587. #endif
  588.     pic->next = pics;
  589.     pic->prev = NULL;
  590.     if(pic->next) pic->next->prev = pic;
  591.  
  592.     pics = pic;
  593.  
  594.     return ret;
  595. }
  596.  
  597.